#include "Pipe.h"
#include <stdlib.h>
#include <string.h>
#include "uotghs_host.h"

volatile Uotghs* g_pUotghsReg = ((Uotghs *)0x400AC000U);

static PipeSize PipeSize_Convert(uint16 size)
{
	const uint16 g_PipeSizeMap[][2] = 
	{
		 {PIPE_SIZE_8	, 8}
		,{PIPE_SIZE_16	, 16}
		,{PIPE_SIZE_32	, 32}
		,{PIPE_SIZE_64	, 64}
		,{PIPE_SIZE_128	, 128}
		,{PIPE_SIZE_256	, 256}
		,{PIPE_SIZE_512	, 512}
		,{PIPE_SIZE_1024, 1024}
	};

	uint32 i = 0;
	for(i = 0; i < sizeof(g_PipeSizeMap) / 4; i++)
	{
		if(g_PipeSizeMap[i][1] == size) 
		{
			return (PipeSize)g_PipeSizeMap[i][0];
		}
	}

	Assert(False);
	return PIPE_MAX;
}

static void SetupUrb_Release(SetupUrb* pSetupUrb)
{
	memset(pSetupUrb, 0, sizeof(SetupUrb));
}

static void SetupUrb_Init(SetupUrb* pSetupUrb, const SetupReq* pReq, const void* payload, uint16 payloadSize, TransDoneFun TxSetupDone, void* pArg)
{
	memset(pSetupUrb, 0, sizeof(SetupUrb));

	pSetupUrb->m_Status 		= URB_STATUS_INIT;
	pSetupUrb->m_pPayLoad 		= (uint8*)payload;
	pSetupUrb->m_PayLoadSize 	= payloadSize;
	pSetupUrb->TransDone 		= TxSetupDone;
	pSetupUrb->m_pArg 			= pArg;
	
	memcpy(&pSetupUrb->m_SetupReq, pReq, sizeof(SetupReq));
}

void Pipe_Start(Pipe* pPipe)
{
	/*
	volatile HostPipeReg* pPipeReg 	= (volatile HostPipeReg*)&g_pUotghsReg->UOTGHS_HSTPIP;
	volatile UotgIntReg* pOtgIntEnReg 	= (volatile UotgIntReg*)&g_pUotghsReg->UOTGHS_HSTIER;

	//Pipe enable
	pPipeReg->asUint32 |= (1 << pPipe->m_PipeNum);
	pOtgIntEnReg->asUint32 |= (UOTGHS_HSTIER_PEP_0 << pPipe->m_PipeNum);
	
	//pPipe->m_pPipeEnReg->rxInDataInt 	= ;
	//pPipe->m_pPipeEnReg->txOutDataInt 	= ;
	//pPipe->m_pPipeEnReg->txSetupOrUnderFlowInt 	= ;
	pPipe->m_pPipeEnReg->pipeErrIntEn 	= 1;	//Pipe Error Interrupt Enable
	//pPipe->m_pPipeEnReg->nakInt 		= ;
	//pPipe->m_pPipeEnReg->overflowInt 	= ;
	pPipe->m_pPipeEnReg->rxStalledOrCrcErrInt = 1;	//Received STALLed Interrupt Enable
	//pPipe->m_pPipeEnReg->shortPktInt 	= ;
	//pPipe->m_pPipeEnReg->busyBankInt 	= ;
	
	//pPipe->m_pPipeEnReg->busyBankInt 	= ;
	//pPipe->m_pPipeEnReg->fifoCtrl 		= ;
	//pPipe->m_pPipeEnReg->pDishDma 		= ;
	//pPipe->m_pPipeEnReg->pipeFreeze 	= ;
*/	
	uhd_enable_pipe(pPipe->m_PipeNum);
	uhd_enable_stall_interrupt(pPipe->m_PipeNum);
	uhd_enable_pipe_error_interrupt(pPipe->m_PipeNum);
	uhd_enable_pipe_interrupt(pPipe->m_PipeNum);
}

static void Pipe_Isr(Pipe* pPipe)
{
}

Bool Pipe_Init(Pipe* pPipe, uint8 addr, uint8 pipeNum, uint16 size)
{
	HostAddr* pAddrReg = (HostAddr*)&g_pUotghsReg->UOTGHS_HSTADDR1;

	pPipe->m_PipeNum = pipeNum;
		
	pPipe->m_pPipeCfgReg 	= (volatile HostPipeCfgReg*)&g_pUotghsReg->UOTGHS_HSTPIPCFG[pipeNum];
	pPipe->m_pPipeStatusReg = (volatile HostPipeStatusReg*)&g_pUotghsReg->UOTGHS_HSTPIPISR[pipeNum];
	pPipe->m_pPipeClsReg 	= (volatile HostPipeClsReg*)&g_pUotghsReg->UOTGHS_HSTPIPICR[pipeNum];
	pPipe->m_pPipeSetReg 	= (volatile HostPipeSetReg*)&g_pUotghsReg->UOTGHS_HSTPIPIFR[pipeNum];
	pPipe->m_pPipeMaskReg 	= (volatile HostPipeMaskReg*)&g_pUotghsReg->UOTGHS_HSTPIPIMR[pipeNum];
	
	pPipe->m_pPipeEnReg 	= (volatile HostPipeEnReg*)&g_pUotghsReg->UOTGHS_HSTPIPIER[pipeNum];
	pPipe->m_pPipeDisReg 	= (volatile HostPipeDisReg*)&g_pUotghsReg->UOTGHS_HSTPIPIDR[pipeNum];
	pPipe->m_pPipeInReqReg 	= (volatile HostPipeInReqReg*)&g_pUotghsReg->UOTGHS_HSTPIPINRQ[pipeNum];
	pPipe->m_pPipeErrReg 	= (volatile HostPipeErrReg*)&g_pUotghsReg->UOTGHS_HSTPIPERR[pipeNum];
	

	//Config Pipe
	pPipe->m_pPipeCfgReg->isAllocMem	= 1;
	pPipe->m_pPipeCfgReg->pipeBank		= PIPE_BANK_1;
	pPipe->m_pPipeCfgReg->pipeSize		= PipeSize_Convert(size);
	pPipe->m_pPipeCfgReg->pipeToken		= PIPE_TOKEN_SETUP;
	pPipe->m_pPipeCfgReg->autoSwitch	= False;
	pPipe->m_pPipeCfgReg->pipeType		= PIPE_TYPE_CTRL;
	pPipe->m_pPipeCfgReg->pipeEpNum		= pipeNum;
	pPipe->m_pPipeCfgReg->pingEn		= False;
	pPipe->m_pPipeCfgReg->pipeIntReqFreq = 0;

	if(!pPipe->m_pPipeStatusReg->isCfgOk)
	{
		Assert(pPipe->m_pPipeStatusReg->isCfgOk);
		return false;
	}

	//Set pipe addr.
	pAddrReg[pipeNum].address = addr;

	pPipe->Isr = (PipeFun)Pipe_Isr;
	return True;
	
/*	
{
	uhd_enable_pipe(pipeNum);
	uhd_configure_pipe(pipeNum, // Pipe Num
		0, // No frequency
		epNum, // endpoint Num
		UOTGHS_HSTPIPCFG_PTYPE_BLK,
		isIn ? UOTGHS_HSTPIPCFG_PTOKEN_IN : UOTGHS_HSTPIPCFG_PTOKEN_OUT,
		ep_size,
		UOTGHS_HSTPIPCFG_PBK_2_BANK, 1);

	uhd_allocate_memory(pipeNum);
	if (!Is_uhd_pipe_configured(pipeNum)) {
		uhd_disable_pipe(pipeNum);
		return false;
	}
	uhd_configure_address(pipeNum, add);

	// Always enable stall and error interrupts of control endpoint
	uhd_enable_stall_interrupt(pipeNum);
	uhd_enable_pipe_error_interrupt(pipeNum);
	uhd_enable_pipe_interrupt(pipeNum);
	return true;
}
*/
}
///////////////////////////////////////////////////////////////////////////

static void CtrlPipe_ReqDone(CtrlPipe* pCtrlPipe)
{
	SetupUrb setupUrb;
	SetupUrb* pSetupUrb = &pCtrlPipe->m_SetupUrb;

	memcpy(&setupUrb, pSetupUrb, sizeof(SetupUrb));

	pCtrlPipe->m_TimeOut = 0;

	SetupUrb_Release(pSetupUrb);
	
	// Call callback
	if (setupUrb.TransDone) 
	{
		setupUrb.TransDone(setupUrb.m_pArg, &setupUrb.m_SetupReq, setupUrb.m_ActTransSize, (UsbStatus)setupUrb.m_Status);
	}

}

static void CtrlPipe_PhaseSetup(CtrlPipe* pCtrlPipe, const SetupReq* pReq)
{
	SetupUrb* pSetupUrb = &pCtrlPipe->m_SetupUrb;
	
	union
	{
		volatile uint64_t value64;
		SetupReq req;
	}setup;
	
	volatile uint64_t *ptr_ep_data;
	Pipe* pPipe = (Pipe*)pCtrlPipe;

	memcpy(&setup.req, pReq, sizeof(SetupReq));
	
	setup.req.wValue 	= cpu_to_le16(setup.req.wValue);
	setup.req.wIndex 	= cpu_to_le16(setup.req.wIndex);
	setup.req.wLength 	= cpu_to_le16(setup.req.wLength);

	pCtrlPipe->m_Phase = UHD_CTRL_REQ_PHASE_SETUP;

	if (!Is_uhd_pipe_enabled(pPipe->m_PipeNum))
	{
		pSetupUrb->m_Status = UHD_TRANS_DISCONNECT;
		CtrlPipe_ReqDone(pCtrlPipe);
		return; // Endpoint not valid
	}
	
	// Fill pipe
	uhd_configure_pipe_token(pPipe->m_PipeNum, UOTGHS_HSTPIPCFG_PTOKEN_SETUP);
	
	pPipe->m_pPipeClsReg->transSetupIntCls = 1;
	//uhd_ack_setup_ready(pPipe->m_PipeNum);

	ptr_ep_data = (volatile uint64_t *)&uhd_get_pipe_fifo_access(pPipe->m_PipeNum, 64);
	*ptr_ep_data = setup.value64;

	pCtrlPipe->m_TimeOut = 5000;
	
	pPipe->m_pPipeEnReg->txSetupOrUnderFlowInt = 1;
	//uhd_enable_setup_ready_interrupt(pPipe->m_PipeNum);

	
	pPipe->m_pPipeDisReg->fifoCtrl = 1;  //Send the FIFO data and switch the bank
	//uhd_ack_fifocon(pPipe->m_PipeNum);

	pPipe->m_pPipeDisReg->pipeFreeze = 1;
//	uhd_unfreeze_pipe(pPipe->m_PipeNum);
}

bool CtrlPipe_TxSetupReq(CtrlPipe* pCtrlPipe, const SetupReq* pReq, const void* payload, uint16 payloadSize, TransDoneFun TxSetupDone, void* pArg)
{
	SetupUrb* pSetupUrb = &pCtrlPipe->m_SetupUrb;

	if(URB_STATUS_INIT != pSetupUrb->m_Status)
	{
		return False;
	}

	SetupUrb_Init(pSetupUrb, pReq, payload, payloadSize, TxSetupDone, pArg);
	
	pCtrlPipe->m_isPending = True;
	
	pSetupUrb->m_Status = URB_STATUS_PROCESS;
	CtrlPipe_PhaseSetup(pCtrlPipe, pReq);

	return true;
}

static void CtrlPipe_PhaseZlpOut(CtrlPipe* pCtrlPipe)
{
	Pipe* pPipe = (Pipe*) pCtrlPipe;
	
	pCtrlPipe->m_Phase = UHD_CTRL_REQ_PHASE_ZLP_OUT;
	
	//uhd_configure_pipe_token(0, UOTGHS_HSTPIPCFG_PTOKEN_OUT);
	pPipe->m_pPipeCfgReg->pipeToken = PIPE_TOKEN_OUT;
	
	//uhd_ack_out_ready(0);
	pPipe->m_pPipeClsReg->txOutDataIntCls = 1;
	
	//uhd_enable_out_ready_interrupt(0);
	pPipe->m_pPipeEnReg->txOutDataInt= 1;
		
	//uhd_ack_fifocon(pPipe->m_PipeNum);
	pPipe->m_pPipeDisReg->fifoCtrl = 1;
	
	//uhd_unfreeze_pipe(pPipe->m_PipeNum);
	pPipe->m_pPipeDisReg->pipeFreeze = 1;
}

static void CtrlPipe_PhaseZlpIn(CtrlPipe* pCtrlPipe)
{
	Pipe* pPipe = (Pipe*) pCtrlPipe;
	
	pCtrlPipe->m_Phase = UHD_CTRL_REQ_PHASE_ZLP_IN;
	
	//uhd_configure_pipe_token(pPipe->m_PipeNum, UOTGHS_HSTPIPCFG_PTOKEN_IN);
	pPipe->m_pPipeCfgReg->pipeToken = PIPE_TOKEN_IN;
	
	//uhd_ack_in_received(pPipe->m_PipeNum);
	pPipe->m_pPipeClsReg->rxInDataIntCls = 1;
	
	//uhd_ack_short_packet(pPipe->m_PipeNum);
	pPipe->m_pPipeClsReg->shortPktIntCls = 1;
	
	//uhd_enable_in_received_interrupt(pPipe->m_PipeNum);
	pPipe->m_pPipeEnReg->rxInDataInt = 1;
	
	//uhd_ack_fifocon(pPipe->m_PipeNum);
	pPipe->m_pPipeDisReg->fifoCtrl = 1;
	
	//uhd_unfreeze_pipe(pPipe->m_PipeNum);
	pPipe->m_pPipeDisReg->pipeFreeze = 1;
}

static void CtrlPipe_PhaseDataIn(CtrlPipe* pCtrlPipe)
{
	SetupUrb* pSetupUrb = &pCtrlPipe->m_SetupUrb;
	Pipe* pPipe = (Pipe*) pCtrlPipe;
	bool b_short_packet;
	uint8_t *ptr_ep_data;
	uint8_t nb_byte_received;

	// Get information to read data
	//nb_byte_received = uhd_byte_count(0);
	nb_byte_received = pPipe->m_pPipeStatusReg->pipeByteCount;
	
#ifdef USB_HOST_HUB_SUPPORT
	//! In HUB mode, the control pipe is always configured to 64B
	//! thus the short packet flag must be computed
	b_short_packet = (nb_byte_received != uhd_get_pipe_size(0));
	uhd_ack_short_packet(0);
#else
	//b_short_packet = Is_uhd_short_packet(0);
	b_short_packet = pPipe->m_pPipeStatusReg->shortPktInt;
#endif

	ptr_ep_data = (uint8_t *) & uhd_get_pipe_fifo_access(0, 8);

	// Copy data from pipe to payload buffer
	while (pSetupUrb->m_ActTransSize < pSetupUrb->m_PayLoadSize && nb_byte_received) 
	{
		pSetupUrb->m_pPayLoad[pSetupUrb->m_ActTransSize++] = *ptr_ep_data++;
		nb_byte_received--;
	}

	if(pSetupUrb->m_ActTransSize == pSetupUrb->m_SetupReq.wLength
		|| pPipe->m_pPipeStatusReg->shortPktInt)
	{
		//Transfer payload ending.
		if(b_short_packet)
		{
			pPipe->m_pPipeClsReg->shortPktIntCls = 1;
		}
		pSetupUrb->m_Status = URB_STATUS_SUCCESS;
		CtrlPipe_PhaseZlpOut(pCtrlPipe);
	}
	else if(pSetupUrb->m_ActTransSize < pSetupUrb->m_PayLoadSize)
	{
		pSetupUrb->m_Status = URB_STATUS_FAIL;
		if(nb_byte_received)
		{
			// payload buffer is full
		}
		else	
		{
			//The rsponse of setup req is wrong;
		}
		
		CtrlPipe_PhaseZlpOut(pCtrlPipe);
	}

	// Send a new IN packet request
	//hd_enable_in_received_interrupt(0);
	pPipe->m_pPipeEnReg->rxInDataInt = 1;

	//uhd_ack_fifocon(0);
	pPipe->m_pPipeDisReg->fifoCtrl = 1;

	//uhd_unfreeze_pipe(0);
	pPipe->m_pPipeDisReg->pipeFreeze = 1;

}

static void CtrlPipe_PhaseDataOut(CtrlPipe* pCtrlPipe)
{
	SetupUrb* pSetupUrb = &pCtrlPipe->m_SetupUrb;
	Pipe* pPipe = (Pipe*) pCtrlPipe;
	uint8 *ptr_ep_data;
	uint8 ep_ctrl_size;

	pCtrlPipe->m_Phase = UHD_CTRL_REQ_PHASE_DATA_OUT;

	if (pSetupUrb->m_ActTransSize == pSetupUrb->m_SetupReq.wLength) 
	{
		// End of DATA phase
		pSetupUrb->m_Status = URB_STATUS_SUCCESS;
		CtrlPipe_PhaseZlpIn(pCtrlPipe);
		return;
	}

	ep_ctrl_size = uhd_get_pipe_size(pPipe->m_PipeNum);

	// Fill pipe
	uhd_configure_pipe_token(pPipe->m_PipeNum, UOTGHS_HSTPIPCFG_PTOKEN_OUT);
	uhd_ack_out_ready(pPipe->m_PipeNum);
	ptr_ep_data = (uint8 *) & uhd_get_pipe_fifo_access(pPipe->m_PipeNum, 8);
	
	while(pSetupUrb->m_ActTransSize <= pSetupUrb->m_PayLoadSize && ep_ctrl_size > 0)
	{
		*ptr_ep_data++ = pSetupUrb->m_pPayLoad[pSetupUrb->m_ActTransSize++];
		ep_ctrl_size--;
	}

	pPipe->m_pPipeEnReg->txOutDataInt = 1;
	//uhd_enable_out_ready_interrupt(pPipe->m_PipeNum);
	uhd_ack_fifocon(pPipe->m_PipeNum);
	uhd_unfreeze_pipe(pPipe->m_PipeNum);
}

static void CtrlPipe_isrSetup(CtrlPipe* pCtrlPipe)
{
	Pipe* pPipe = (Pipe*) pCtrlPipe;
	SetupUrb* pSetupUrb = &pCtrlPipe->m_SetupUrb;
	
	// SETUP packet sent
	pPipe->m_pPipeEnReg->pipeFreeze = 1;
	pPipe->m_pPipeEnReg->txSetupOrUnderFlowInt = 1;
	
	// Start DATA phase
	if ((pSetupUrb->m_SetupReq.bmRequestType & USB_REQ_DIR_MASK) == USB_REQ_DIR_IN) 
	{
		CtrlPipe_PhaseDataIn(pCtrlPipe);
	} 
	else
	{
		if (pSetupUrb->m_SetupReq.wLength) 
		{
			CtrlPipe_PhaseDataOut(pCtrlPipe);
		} 
		else 
		{
			// No DATA phase
			CtrlPipe_PhaseZlpOut(pCtrlPipe);
		}
	}
	return;
}

static void CtrlPipe_isrRxInData(CtrlPipe* pCtrlPipe)
{
	Pipe* pPipe = (Pipe*) pCtrlPipe;
	
	// In case of low USB speed and with a high CPU frequency,
	// a ACK from host can be always running on USB line
	// then wait end of ACK on IN pipe.
	
	//while (!Is_uhd_pipe_frozen(0));
	while (!pPipe->m_pPipeMaskReg->pipeFreeze);
	
	switch(pCtrlPipe->m_Phase) 
	{
	case UHD_CTRL_REQ_PHASE_DATA_IN:
		CtrlPipe_PhaseDataIn(pCtrlPipe);
		break;
	case UHD_CTRL_REQ_PHASE_ZLP_IN:
		CtrlPipe_ReqDone(pCtrlPipe);
		break;
	default:
		break;
	}
}

static void CtrlPipe_isrTxOutData(CtrlPipe* pCtrlPipe)
{
	Pipe* pPipe = (Pipe*) pCtrlPipe;
	
	// OUT packet sent
	//uhd_freeze_pipe(0);
	pPipe->m_pPipeEnReg->pipeFreeze = 1;
	
	switch(pCtrlPipe->m_Phase) 
	{
	case UHD_CTRL_REQ_PHASE_DATA_OUT:
		CtrlPipe_PhaseDataOut(pCtrlPipe);
		break;
	case UHD_CTRL_REQ_PHASE_ZLP_OUT:
		CtrlPipe_ReqDone(pCtrlPipe);
		break;
	default:
		break;
	}
	return;
}

static void CtrlPipe_isrStalled(CtrlPipe* pCtrlPipe)
{
	//Pipe* pPipe = (Pipe*) pCtrlPipe;
	SetupUrb* pSetupUrb = &pCtrlPipe->m_SetupUrb;

	pSetupUrb->m_Status = URB_STATUS_STALL;
		
	CtrlPipe_ReqDone(pCtrlPipe);
	return;
}

static void CtrlPipe_isrPipeErr(CtrlPipe* pCtrlPipe)
{
	Pipe* pPipe = (Pipe*) pCtrlPipe;
	// Get and ack error
	//uhd_ctrl_request_end(uhd_pipe_get_error(0));
        pCtrlPipe->m_SetupUrb.m_Status = uhd_pipe_get_error(0);
	CtrlPipe_ReqDone(pCtrlPipe);
	pPipe->m_pPipeClsReg->stalledOrCrcErrIntCls = 1;
	return;
}

void CtrlPipe_isr(CtrlPipe* pCtrlPipe)
{
	Pipe* pPipe = (Pipe*) pCtrlPipe;
	
	// Disable setup, IN and OUT interrupts of control endpoint
	pPipe->m_pPipeDisReg->rxInDataInt = 1;
	pPipe->m_pPipeDisReg->txOutDataInt = 1;
	pPipe->m_pPipeDisReg->transSetupInt = 1;

	if(pPipe->m_pPipeStatusReg->transSetupInt)	//Transmitted SETUP Interrupt
	{
		CtrlPipe_isrSetup(pCtrlPipe);
		pPipe->m_pPipeClsReg->transSetupIntCls = 1;
		return;
	}

	if (pPipe->m_pPipeStatusReg->rxInDataInt) 	//Received IN Data Interrupt
	{
		CtrlPipe_isrRxInData(pCtrlPipe);
		pPipe->m_pPipeClsReg->rxInDataIntCls = 1;
		return;
	}
	
	if (pPipe->m_pPipeStatusReg->txOutDataInt) 	//Transmitted OUT Data Interrupt
	{
		CtrlPipe_isrTxOutData(pCtrlPipe);
		pPipe->m_pPipeClsReg->txOutDataIntCls = 1;
		return;
	}
	
	if (pPipe->m_pPipeStatusReg->rcvStalledOrCrcErrInt) 	//Received STALLed Interrupt
	{
		CtrlPipe_isrStalled(pCtrlPipe);
		pPipe->m_pPipeClsReg->stalledOrCrcErrIntCls = 1;
		return;
	}
	
	if (pPipe->m_pPipeStatusReg->pipeErrInt) 	//Pipe Error Interrupt
	{
		CtrlPipe_isrPipeErr(pCtrlPipe);
		return;
	}
}
void CtrlPipe_Init(CtrlPipe* pCtrlPipe, uint8 addr, uint8 pipeNum)
{
	Pipe* pPipe = (Pipe*)pCtrlPipe;

	memset(pCtrlPipe, 0, sizeof(CtrlPipe));
	
	Pipe_Init(pPipe, addr, pipeNum, 64);

	pPipe->Isr = (PipeFun)CtrlPipe_isr;
	
	pPipe->m_pPipeCfgReg->pipeToken		= PIPE_TOKEN_SETUP;
}

///////////////////////////////////////////////////////////////////////////
void BlkInPipe_Init(BlkInPipe* pBlkInPipe, uint8 addr, uint8 pipeNum, uint16 pktSize)
{
	Pipe* pPipe = (Pipe*)pBlkInPipe;
	
	Pipe_Init(pPipe, addr, pipeNum, pktSize);
	
	pPipe->m_pPipeCfgReg->pipeToken		= PIPE_TOKEN_IN;
	pPipe->m_pPipeCfgReg->pipeBank		= PIPE_BANK_2;
	pPipe->m_pPipeCfgReg->autoSwitch	= True;
}

///////////////////////////////////////////////////////////////////////////
void BlkOutPipe_Init(BlkOutPipe* pBlkOutPipe, uint8 addr, uint8 pipeNum, uint16 pktSize)
{
	Pipe* pPipe = (Pipe*)pBlkOutPipe;
	
	Pipe_Init(pPipe, addr, pipeNum, pktSize);
	
	pPipe->m_pPipeCfgReg->pipeToken		= PIPE_TOKEN_OUT;
	pPipe->m_pPipeCfgReg->pipeBank		= PIPE_BANK_2;
	pPipe->m_pPipeCfgReg->autoSwitch	= True;
	pPipe->m_pPipeCfgReg->pingEn		= True;
}

